#pragma once

#include <cstdint>

namespace SL
{

class RenderResourceHandle
{};
class ShaderArgument
{};
#define MAX_SHADER_PARAMETERS 32

enum class RenderCommandQueueType : uint8_t
{
    None = 0x00,
    Copy = 0x01,
    Compute = 0x02,
    Graphics = 0x04,
    All = Copy | Compute | Graphics
};

enum class RenderCommandType : uint8_t
{
    // draws
    Draw,
    DrawIndirect,
    Dispatch,
    DispatchIndirect,

    // uploading
    UpdateBuffer,
    UpdateTexture,  
    CopyBuffer,
    CopyTexture,

    // synchronization
    Barriers,    // ?

    // profiling
    BeginTiming,
    EndTiming,
    ResolveTimings,
    BeginEvent,
    EndEvent,
    BeginRenderPass, // setup states, set heap
    EndRenderPass,

    // raytrace
    RayTrace,
    UpdateTopLevel,
    UpdateBottomLevel,
    UpdateShaderTable,

    Count,
};

/**
 * @brief
 * render command is typed for verification
 */
struct RenderCommand
{
    RenderCommandType type = RenderCommandType::Count;
};

/*
    High-level stateless RenderCommands
*/

template<RenderCommandType TYPE, RenderCommandQueueType QUEUE_TYPE>
struct RenderCommandTyped : RenderCommand
{
    static const RenderCommandType Type = TYPE;
    static const RenderCommandQueueType QueueType = QUEUE_TYPE;

    RenderCommandTyped() { type = Type; }
};

struct RenderCommandDraw : RenderCommandTyped<RenderCommandType::Draw, RenderCommandQueueType::Graphics>
{
    RenderResourceHandle pipelineState;
    ShaderArgument shaderArgument[MAX_SHADER_PARAMETERS];
};

struct RenderCommandDrawIndirect : RenderCommandTyped<RenderCommandType::DrawIndirect, RenderCommandQueueType::Graphics>
{
    RenderResourceHandle pipelineState;
    ShaderArgument shaderArgument[MAX_SHADER_PARAMETERS];
};

struct RenderCommandDispatch : RenderCommandTyped<RenderCommandType::Dispatch, RenderCommandQueueType::Compute>
{
    RenderResourceHandle pipelineState;
    ShaderArgument shaderArgument[MAX_SHADER_PARAMETERS];
    uint32_t shaderArgumentCount = 0;

    uint32_t dispatchX = 0;
    uint32_t dispatchY = 0;
    uint32_t dispatchZ = 0;
};

struct RenderCommandDispatchIndirect : RenderCommandTyped<RenderCommandType::DispatchIndirect, RenderCommandQueueType::Compute>
{
    RenderResourceHandle pipelineState;
    ShaderArgument shaderArgument[MAX_SHADER_PARAMETERS];
    uint32_t shaderArgumentCount = 0;

    uint32_t dispatchX = 0;
    uint32_t dispatchY = 0;
    uint32_t dispatchZ = 0;
};

struct RenderCommandCopyTexture : RenderCommandTyped<RenderCommandType::CopyTexture, RenderCommandQueueType::Copy>
{};

struct RenderCommandCopyBuffer : RenderCommandTyped<RenderCommandType::CopyBuffer, RenderCommandQueueType::Copy>
{};

struct RenderCommandTransitions : RenderCommandTyped<RenderCommandType::Transitions, RenderCommandQueueType::Graphics>
{};

struct RenderCommandBeginRenderPass : RenderCommandTyped<RenderCommandType::BeginRenderPass, RenderCommandQueueType::Graphics>
{};

struct RenderCommandEndRenderPass : RenderCommandTyped<RenderCommandType::EndRenderPass, RenderCommandQueueType::Graphics>
{};


} // namespace SL